package tij4.concurrent.exercise.ex24;

/*
    不控制消费者和生产者的相对速度
    生产者不能溢出接受者的缓存区,
    而这在生产者比消费者速度快时完全有可能发生;
    如果消费者比生产者的速度快,
    那么消费者不能读取多次相同的数据.
 */

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class Item {
    private final int itemNum;

    public Item(int itemNum) {
        this.itemNum = itemNum;
    }

    @Override
    public String toString() {
        return "Item " + itemNum;
    }
}

class Producer implements Runnable {
    private int count = 0;
    Market24 market;

    Producer(Market24 market) {
        market = market;
    }

    public int getCount() {
        return count;
    }

    @Override
    public void run() {
        while (!Thread.interrupted()) {
            try {
                while (count < 100) {
                    Item item = new Item(++count);
                    if (market.storage.offer(item)) {
                        System.out.println("Producer " + item);
                        synchronized (market.consumer) {
                            market.consumer.notifyAll();
                        }
                    }
                    synchronized (this) {
                        while (!(market.storage.size() < 10)) {
                            wait();
                        }
                    }
                }
                System.out.println("Produced " + count + " Items" + "\nStopping production");
                market.exec.shutdownNow();
            }catch (InterruptedException e) {
                System.out.println("Porudct interruped");
                System.out.println("Porudct " + count +  " Items");
            }
        }
    }
}

class Consumer implements Runnable {
    int consumed = 0;
    Market24 market;
    List<Item> cart = new ArrayList<Item>();

    Consumer(Market24 market) {
        this.market = market;
    }

    @Override
    public void run() {
        try {
            while (!Thread.interrupted()) {
                synchronized (this) {
                    while (!(cart.size() < market.producer.getCount())) {
                        wait();
                    }
                }
                if(cart.add(market.storage.poll())) {
                    System.out.println("Consuming Item " + ++consumed);
                    synchronized (market.producer) {
                        market.producer.notifyAll();
                    }
                }
            }
        }catch (InterruptedException e) {
            System.out.println("Consumer interrupted");
            System.out.println("Consumer " + consumed + " Items");
        }
    }
}
public class Market24 {
    ExecutorService exec = Executors.newCachedThreadPool();
    Queue<Item> storage = new LinkedList<>();
    Producer producer = new Producer(this);
    Consumer consumer = new Consumer(this);
    public Market24() {
        exec.execute(producer);
        exec.execute(consumer);
    }

    public static void main(String[] args) {
        new Market24();
    }
}
